<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <user-card data-open="true"></user-card>
    <template id="userCardTemplate">
        <style>
            .container {
                background: #eee;
                border-radius: 10px;
                width: 500px;
                padding: 20px;
            }
        </style>
        <div class="container">
            <p class="name" data-open="true">{{name}}</p><p class="email">{{email}}<span>{{email}}</span></p>
            <input type="text" v-model="message">
            <span>{{message}}</span>
            <button class="button">Follow</button>
        </div>
    </template>
    <script>
        class popEvent{
            constructor(option){
                /*
                * 接收四个参数：
                * 1，对象的this
                * 2，要监听的元素
                * 3，要监听的事件,默认监听点击事件
                * 4，是否冒泡
                * */
                this.eventObj = option.obj;
                this.target = option.target || this.eventObj;
                this.eventType = option.eventType || 'click';
                this.popup = option.popup || false;
                this.bindEvent();
            }
            bindEvent(){
                let _this = this;
                _this.target.addEventListener(_this.eventType,function(ev){
                    let target = ev.target;
                    let dataset,parent,num,b;
                    popup(target);
                    function popup(obj){
                        
                        if(obj === document){ return false;}
                        dataset = obj.dataset;
                        num = Object.keys(dataset).length;
                        parent = obj.parentNode;
                        if(num<1){
                            _this.popup && popup(parent);
                            num = 0;
                        }else{
                            for(b in dataset){
                                if(_this.eventObj.__proto__[b]){
                                    _this.eventObj.__proto__[b].call(_this.eventObj,{obj:obj,ev:ev,target:dataset[b],data:_this.eventObj});
                                }
                            }
                            _this.popup && popup(parent);
                        }
                    }
                },false)
            }
        }

        class UserCard extends HTMLElement{
            constructor() {
                super();
                var templateElem = document.getElementById('userCardTemplate');
                
                var content = templateElem.content.cloneNode(true);
                this.appendChild(content);

                this._data = {
                    name:'用户名',
                    email:'yourmail@some-email.com',
                    message:'双向'
                }
                
                this.compileNode(this);
                this.observe();
                this.bindEvent();//处理事件

            }
            bindEvent(){
                this.event = new popEvent({
                    obj:this,
                    popup:true
                });
            }
            compileNode(el){
                let child = el.childNodes;
                // let child = el.childNodes[3];//获取到所有的子元素
                // child=child.childNodes;
                [...child].forEach((node)=>{//利用展开运算符直接转换成数组然后forEach
                    let text = node.textContent?node.textContent.replace(/(^\s*)|(\s*$)/g, ""):'';
                    if(node.nodeType === 3 && text ){
                        let reg = /\{\{\s*([^\s\{\}]+)\s*\}\}/g;
                        //大概的意思就是匹配前面有两个{{,后面也有两个}}的这么一串文本
                        console.log("text",text)
                        if(reg.test(text)){//如果能找到这样的字符串
                            console.log("RegExp",RegExp.$1)
                            let $1 = RegExp.$1;//那就把里面的内容拿出来，比如‘name’
                            this._data[$1] && (node.textContent = text.replace(reg,this._data[$1]));//看看数据里面有没有name这么个东西，如果有，那就把数据里面name对应的值填到当前这个位置。
                            
                            this.addEventListener($1,(e)=>{
                                node.textContent=text.replace(reg,e.detail)
                            })
                        };
                    }else if(node.nodeType === 1){
                        let attrs = node.attributes;
                        console.log("attrs",attrs);
                        if(attrs.hasOwnProperty('v-model')){//判断是不是有这个属性
                            let keyname = attrs['v-model'].nodeValue;
                            node.value = this._data[keyname];
                            node.addEventListener('input',e=>{//如果有，监听事件，修改数据
                                this._data[keyname] = node.value;//修改数据
                            });
                        }

                        if(node.childNodes.length > 0){
                            this.compileNode(node);//递归实现深度解析
                        }
                    }

                })
            }
            observe(){
                let _this=this;
                this._data=new Proxy(this._data,{
                    set(obj,prop,value){
                        //事件通知机制，发生改变的时候，通过自定义事件通知视图发生改变
                        let event = new CustomEvent(prop,{
                            detail: value//注意这里我传了个detail过去，这样的话更新视图的时候就可以直接拿到新的数据
                        });
                        _this.dispatchEvent(event);
                        return Reflect.set(...arguments);//这里是为了确保修改成功,不写其实也没关系

                    }
                })
            }
            open(){
                console.log('触发了open方法');
            }
        }
        window.customElements.define('user-card',UserCard);
        
        let card = document.querySelector('user-card');
        document.onclick = function(){
            console.log('点击了');
            card._data.name = '新的用户名';
        }
    </script>
</body>
</html>